﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicalRig : MonoBehaviour
{
    public Transform[] bones;
    public string[] chainCodes;
    public List<Chain> chains;
    public bool flatBonesOnStart;
    public bool physicsOn = true;
    public float stiffnessFactor = 5f;
    public float dragFactor = 10;
    public Vector3 gravity = new Vector3(0, -0.3f, 0);
    public int iterCount = 10;
    public bool oneWaySpring;
    public bool oneWayResetLength;
    public bool oneWaykeepLookAt;
    [Header("Debug")]
    public bool debugDrawDir;
    public bool debugDrawOneWay;
    public float oneWayBoneLength = 0.05f;
    [ContextMenu("FlatBones()")]
    void FlatBones() // exclude Scale
    {
        var poss = new List<Tran2>();
        foreach (var bone in bones)
        {
            poss.Add(bone.Tran2());
        }
        foreach (var bone in bones)
        {
            bone.SetParent(transform);
        }
        var e = poss.GetEnumerator();
        foreach (var bone in bones)
        {
            e.MoveNext();
            bone.SetTran2(e.Current);
        }
    }
    void Start()
    {
        if (flatBonesOnStart) FlatBones();
        if (chainCodes == null) return;
        chains = new List<Chain>();
        foreach (var code in chainCodes)
        {
            var chain = new Chain();
            chains.Add(chain);

            var parts = code.Split('p');
            var verts = new List<Transform>(); // 根据文本获取骨骼链
            for (int i = 0; i < parts[0].Length; i++)
            {
                var index = int.Parse(parts[0].Substring(i, 1)) - 1;
                verts.Add(bones[index]);
            }
            chain.space = 1;
            chain.InitEdgeSetting(verts); // 将骨骼链转换成Chain里的边集
            if (parts.Length < 2) continue;
            for (int i = 0; i < parts[1].Length; i++)
            {
                var index = int.Parse(parts[1].Substring(i, 1)) - 1;
                chain.pins[index] = true; // 不作用物理的固定点
            }
        }
    }
    void Update()
    {
        if (physicsOn)
        {
            var dt = Time.deltaTime / iterCount;
            foreach (var chain in chains)
            {
                chain.ClearForce();
                chain.AddGobalForce(gravity); // 重力                
                if (oneWaySpring) chain.OneWaySpring(stiffnessFactor);
                else chain.UpdateSpring(stiffnessFactor);
                chain.AddDragForce(dragFactor); // 阻力
                for (int i = 0; i < iterCount; i++)
                {
                    chain.UpdateForceToVerts(dt);
                }
                if (oneWayResetLength) chain.OneWayResetLength();
                if (oneWaykeepLookAt) chain.FixLookAt();
                chain.debugDrawDir = debugDrawDir;
                chain.debugDrawOneWay = debugDrawOneWay;
                chain.oneWayBoneLength = oneWayBoneLength;
            }
        }
    }
}
